<?php

namespace Common\Util;

/**
 * OSS
 */
class Oss
{

    const BIG_FILE_SIZE = 20971520;#b

    public static function Client()
    {
        $config = C("oss");
        Vendor('Oss.autoload');
        return new \OSS\OssClient($config['accessId'], $config['accessKey'], $config['end_point']);
    }

    /**
     * 上传文件
     * @param filename 上传后的文件名
     * @param file 本地文件地址
     * @return mix
     */
    public static function upload($filename, $file)
    {
        $config = C("oss");

        if( self::BIG_FILE_SIZE < filesize($file) )
        {
            return self::partUpload($filename, $file,$config['bucket']);
        }

        try {
            $res = self::Client()->uploadFile($config['bucket'], $filename, $file);
        } catch (\Exception $e) {
            throw $e;
        }
        return self::parseResult($res);
    }

    /**
     * 上传视频
     * @param filename 上传后的文件名
     * @param file 本地文件地址
     * @return mix
     */
    public static function uploadVideo($filename, $file)
    {
        $config = C("oss");
        if( self::BIG_FILE_SIZE < filesize($file) )
        {
            return self::partUpload($filename, $file,$config['video_bucket']);
        }
        try {
            $res = self::Client()->uploadFile($config['video_bucket'], $filename, $file);
        } catch (\Exception $e) {
            throw $e;
        }
        return self::parseResult($res);
    }

    /**
     * 分片上传 
     * @param filename
     * @param file
     * @return bool|url
     */
    public static function partUpload($filename, $file, $bucket = "")
    {
        // 初始化分片上传
        if (empty($bucket)) {
            $config = C("oss");
            $bucket = $config['bucket'];
        }

        try {
            // 返回uploadId，它是分片上传事件的唯一标识
            // 可以根据这个ID来发起相关的操作，如取消分片上传、查询分片上传等。
            $ossClient = self::Client();
            $object = $filename;
            $uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
            $uploadFile = $file;
            $partSize = 10 * 1024 * 1024;
            $uploadFileSize = filesize($uploadFile);
            $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
            $responseUploadPart = array();
            $uploadPosition = 0;
            $isCheckMd5 = true;
            foreach ($pieces as $i => $piece) {
                $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
                $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
                $upOptions = array(
                    $ossClient::OSS_FILE_UPLOAD => $uploadFile,
                    $ossClient::OSS_PART_NUM => ($i + 1),
                    $ossClient::OSS_SEEK_TO => $fromPos,
                    $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
                    $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
                );
                // MD5校验。
                if ($isCheckMd5) {
                    $contentMd5 = \OSS\Core\OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
                    $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
                }
                // 上传分片。
                $responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
            }
            // $uploadParts是由每个分片的ETag和分片号（PartNumber）组成的数组。
            $uploadParts = array();
            foreach ($responseUploadPart as $i => $eTag) {
                $uploadParts[] = array(
                    'PartNumber' => ($i + 1),
                    'ETag' => $eTag,
                );
            }

            // 在执行该操作时，需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
            $res = $ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
        } catch (\Exception $e) {
            throw $e;
        }
        return self::parseResult($res);
    }

    /**
     * 构造上传文件的返回路径
     * @param ossResult
     * @return bool|url
     */
    public static function parseResult($ossResult)
    {
        if (!$ossResult || !isset($ossResult['oss-request-url']) || empty($ossResult['oss-request-url'])) {
            return false;
        }

        if (!empty(CDN_URL)) {
            $reg = '/(http[s]?\:\/\/[^\/]*\/)/';
            if (substr(CDN_URL, -1) == "/") {
                $domain = CDN_URL;
            } else {
                $domain = CDN_URL . "/";
            }
            $ossResult['oss-request-url'] = preg_replace($reg, $domain, $ossResult['oss-request-url']);
        }

        #去除链接后面的东西
        $ossResult['oss-request-url'] = preg_replace('/(.*?[^\?])\?.*?$/', '$1', $ossResult['oss-request-url']);
        return $ossResult['oss-request-url'];
    }


}